﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.ServiceProcess;
using System.Text;

namespace AnyExeTo.WindowsService
{
    /// <summary>
    /// 任意可执行程序服务
    /// </summary>
    public partial class AnyExeToService : ServiceBase
    {
        /// <summary>
        /// 当前进程
        /// </summary>
        private Process _anyExeProcess;

        /// <summary>
        /// 停止已经调用
        /// </summary>
        private bool _stoped;

        /// <summary>
        /// 日志
        /// </summary>
        private readonly EventLog _eventLog;

        /// <summary>
        /// 初始化 任意可执行程序服务
        /// </summary>
        public AnyExeToService()
        {
            InitializeComponent();
            // 初始化事件日志（可选，也可以使用其他日志库）
            _eventLog = new EventLog();
            var options = ServiceOptions.LoadFromFile();
            var source = $"{ServiceName}-{options.ServiceName}";
            if (!EventLog.SourceExists(source))
            {
                EventLog.CreateEventSource(source, "Application");
            }
            _eventLog.Source = source;
            _eventLog.Log = "Application";
        }

        protected override void OnStart(string[] args)
        {
            _stoped = false;
            var options = ServiceOptions.LoadFromFile();
            if (!string.IsNullOrWhiteSpace(options.ExeFileName))
            {
                if (File.Exists(options.ExeFileName))
                {
                    var processStartInfo = new ProcessStartInfo(options.ExeFileName);
                    if (!string.IsNullOrWhiteSpace(options.StartArguments))
                    {
                        processStartInfo.Arguments = options.StartArguments;
                    }
                    processStartInfo.UseShellExecute = false;
                    processStartInfo.CreateNoWindow = true;
                    processStartInfo.WorkingDirectory = Path.GetDirectoryName(options.ExeFileName) ?? string.Empty;
                    _anyExeProcess = Process.Start(processStartInfo);
                    if (_anyExeProcess != null)
                    {
                        _anyExeProcess.EnableRaisingEvents = true;
                        _anyExeProcess.Exited += AnyExeProcessExited;
                    }
                }
            }
        }

        private void AnyExeProcessExited(object sender, EventArgs e)
        {
            if (!_stoped)
            {
                _eventLog.WriteEntry("AnyExeProcessExited");
                Stop();
            }
        }

        protected override void OnStop()
        {
            // 服务方法由 SCM 控制时，默认超时时间 30 秒。
            // 使用 RequestAdditionalTime() 方法可以额外的请求挂起时间，最长时间 240 秒左右。
            // 具体的时间需要看 Windows 版本
            _stoped = true;
            var options = ServiceOptions.LoadFromFile();
            if (_anyExeProcess != null)
            {
                if (!_anyExeProcess.HasExited)
                {
                    if (options.UseCloseMainWindow)
                    {
                        _anyExeProcess.CloseMainWindow();
                        RequestAdditionalTime(10000);
                        _anyExeProcess.WaitForExit(10000);
                        if (!_anyExeProcess.HasExited)
                        {
                            _anyExeProcess.Kill();
                            _eventLog.WriteEntry("OnStop UseCloseMainWindow AnyExeProcess Kill");
                        }
                    }
                    else if (!string.IsNullOrWhiteSpace(options.CloseArguments))
                    {
                        var processStartInfo = new ProcessStartInfo(_anyExeProcess.StartInfo.FileName);
                        processStartInfo.Arguments = options.CloseArguments;
                        processStartInfo.UseShellExecute = false;
                        processStartInfo.CreateNoWindow = true;
                        processStartInfo.WorkingDirectory = Path.GetDirectoryName(options.ExeFileName) ?? string.Empty;
                        var closeProcess = Process.Start(processStartInfo);
                        if (closeProcess != null)
                        {
                            RequestAdditionalTime(10000);
                            closeProcess.WaitForExit(10000);
                            if (!closeProcess.HasExited)
                            {
                                closeProcess.Kill();
                                _eventLog.WriteEntry("OnStop CloseArguments CloseProcess Kill");
                            }
                        }

                        if (!_anyExeProcess.HasExited)
                        {
                            RequestAdditionalTime(10000);
                            _anyExeProcess.WaitForExit(10000);
                            if (!_anyExeProcess.HasExited)
                            {
                                _anyExeProcess.Kill();
                                _eventLog.WriteEntry("OnStop CloseArguments AnyExeProcess Kill");
                            }
                        }
                    }
                    else if (!_anyExeProcess.HasExited)
                    {
                        _anyExeProcess.Kill();
                        _eventLog.WriteEntry("OnStop AnyExeProcess Kill");
                    }
                }
            }
        }
    }
}
